
#include <vector>


#include "xmlreader.h"

#include "MyGraphClass.h"
#include "MyVertexClass.h"

using namespace std;


string LEARNING_STR(int i){
    switch(i){
        case MULTIPLY_K:
            return("multiply by K");
        case NOTHING_TODO:
            return("do nothing");
        default:
            return("unknown");
    }
}

MyGraph::MyGraph(int GiveSize){
    MyVertex temp;
    int i;
    for(i=0;i<GiveSize;i++){
        VVertices.push_back(temp);
    }
}
int MyGraph::Resize(int n){
    MyVertex temp;
    while(n>VVertices.size()){
        VVertices.push_back(temp);
    }
    while(n<VVertices.size()){
        VVertices.pop_back();
    }
    return(0);
}

MyGraph::~MyGraph(){

}

void MyGraph::AddConnection(int iFrom,int iTo,double dweight){
    VVertices[iFrom].ConnectTo(iTo,dweight);
    //VVertices[iFrom].ShowNext();
}

void MyGraph::ShowVertices(){
    int i;
    cout << "******************************************************" << endl;
    cout << "AFFICHAGE DU GRAPH" << endl;
    cout << "******************************************************" << endl;
    cout << "Nombre de sommets:\t" << NumberVertices() << endl;
    
    for(i=0;i<NumberVertices();i++){
        cout << "============================================" << endl;
        cout << "Sommet\t" << i << " Name: " << VVertices[i].GetName() << endl;
        cout << "---------------------" << endl;
        VVertices[i].ShowNext();
        cout << "============================================" << endl;
    }
    cout << "******************************************************" << endl;
}

void MyGraph::ExploreQueue(int FirstVertex){
    queue<int> TheQueue;
    list<int> temp;
    list<int>::iterator it;
    int i;
    
    
    TheQueue.push(FirstVertex);
    VVertices[FirstVertex].SetMarker(1);
    ShowQueue(TheQueue);
    
    
    while(TheQueue.size()>0){
        temp=VVertices[TheQueue.front()].GetNext();
        it=temp.begin();
        while(it!=temp.end()){
            if(VVertices[*it].GetMarker()==0){
                TheQueue.push(*it);
                VVertices[*it].SetMarker(1);
            }
            else{
            }
            it++;
        }
        TheQueue.pop();
        ShowQueue(TheQueue);
    }
    
    ClearMarker();
    
}
void MyGraph::ExploreQueue(){
    ExploreQueue(0);
}


void MyGraph::ClearMarker(){
    int i;
    for(i=0;i<VVertices.size();i++){
        VVertices[i].SetMarker(0);
    }
}

void MyGraph::ShowQueue(queue<int> TheQueue){
    queue<int> temp;
    temp=TheQueue;
    cout << "------------------------------------" << endl;
    cout << "Status de la file (FIFO)" << endl;
    cout << "------------------------------------" << endl;
    while(temp.size()>0){
        cout << temp.front() << "\t";
        temp.pop();
    }
    cout << endl << "------------------------------------" << endl;
}

void MyGraph::ExploreStack(int FirstVertex){
    stack<int> TheStack;
    list<int>::iterator it;
    list<int> temp;
    
    TheStack.push(FirstVertex);
    VVertices[FirstVertex].SetMarker(1);
    
    while(TheStack.size()>0){
         temp=VVertices[TheStack.top()].GetNext();
         cout << "top" << TheStack.top() << endl;
         it=temp.begin();
         while(true){
             if(it!=temp.end()){
                if(VVertices[*it].GetMarker()==0){
                    TheStack.push(*it);
                    VVertices[*it].SetMarker(1);
                    break;
                }
                it++;
             }
             else{
                TheStack.pop();
                break;
             }
         }
         
         ShowStack(TheStack);
    }
}

void MyGraph::ExploreStack(){
    ExploreStack(0);
}

void MyGraph::ShowStack(stack<int> TheStack){
    stack<int> temp;
    temp=TheStack;
    cout << "------------------------------------" << endl;
    cout << "Status de la file (FIFO)" << endl;
    cout << "------------------------------------" << endl;
    while(temp.size()>0){
        cout << temp.top() << "\t";
        temp.pop();
    }
    cout << endl << "------------------------------------" << endl;
}

int MyGraph::LoadLinks(string fname){
	int node1,node2;
	double theweight;
	ostringstream temp;
	
	thisfname_links	=	fname;
	
	ifstream fin(fname.data());
	
	
	if(fin.fail()==true){
		cout << fname << " NOT FOUND!"  << endl;
		return(-1);
	}
	while(fin.eof()==false){
		fin >> node1;
		fin >> node2;
		fin >> theweight;
		AddConnection(node1,node2,theweight);
		temp.str("");
		temp << node1;
		VVertices[node1].SetName(temp.str());
		temp.str("");
		temp << node2;
		VVertices[node2].SetName(temp.str());
	}
	return(0);
}

int MyGraph::LoadNames(string fname){
	int node;
	string thename;
	
	thisfname_names	=	fname;
	
	ifstream fin(fname.data());
	
	
	if(fin.fail()==true){
		cout << fname << " NOT FOUND!"  << endl;
		return(-1);
	}
	while(fin.eof()==false){
		fin >> node;
		fin >> thename;
		VVertices[node].SetName(thename);
	}
	return(0);
}

string MyGraph::getName(int i){
	if(i<NumberVertices()){
		return(VVertices[i].GetName());
	}
	else{
		return("Unnamed");
	}
}

int MyGraph::ProduceDotFile(){
	int i;
	ofstream fout("out.dot");
	list<int> temp;
	list<double> tempw;
	list<int>::iterator it;
	list<double>::iterator itw;
	
	
	fout << "digraph G{" << endl << "ratio=1.333;" << endl;
	
	for(i=0;i<NumberVertices();i++){
		fout << "\"" << VVertices[i].GetName() << "\"[color="<< VVertices[i].GetColor() <<"];" << endl;
	}
	
	for(i=0;i<NumberVertices();i++){
		temp	=	VVertices[i].GetNext();
		tempw	=	VVertices[i].GetWeight();
		it	=	temp.begin();
		itw	=	tempw.begin();
		while(it!=temp.end()){
			fout << "\"" << VVertices[i].GetName() << "\"->\""<< VVertices[*it].GetName() << "\" [label=" << *itw  <<"];" << endl;
			it++;
			itw++;
		}
	}
	
	fout << "}" << endl;
	
	//system("dot -Tpng out.dot -o out.png");
	
	return(0);
}
int MyGraph::SortNext(){
	int i;
	for(i=0;i<NumberVertices();i++){
		VVertices[i].SortNext(true);
	}
	return(0);
}
int MyGraph::SortNext(int inode, bool Permute){
	return(VVertices[inode].SortNext(Permute));
}

int MyGraph::getNext(int inode,int nextnum){
	return(VVertices[inode].getNext(nextnum-1));
}

int MyGraph::Reload(){
	VVertices.clear();
	LoadLinks(thisfname_links);
	LoadNames(thisfname_names);
	return(0);
}


int MyGraph::Learn(int i_0,int i_1,int i_k){
	//LES i DOIVENT COMMENCER A 0
	double temp,total;
	int i,n_lines,n_block,j;
	vector<double> matrix;
	vector<double> w;
	ifstream fin;
	ostringstream fname;
	vector<double> v1,vk;
	
	
	//LOAD THE WEIGHTS
	
	
	ifstream fw("weight.dat");
	if(fw.fail()){
		return(-1);
	}
	while(fw.eof()==false){
		fw >> temp;
		w.push_back(temp);
	}
	fw.close();
	//LOAD THE VECTORS
	j=0;
	for(i=1;i<=w.size();i++){
		fname.str("");
		fname << "results" << i << ".dat";
		cout << "Opening " << fname.str().data() << endl;
		fin.open(fname.str().data());
		if(fin.fail()){
			cout << "NOT FOUND: " << fname.str().data() << endl;
			return(-1);
		}
		
		while(fin.eof()==false){
			fin >> temp;
			matrix.push_back(temp);
			j++;
		}
		if(i==1){
			n_lines	=(int)floor(sqrt(j));
			n_block	=j;
			cout << n_lines << "," << n_block << endl;
		}
		fin.close();
	}
	
	for(i=0;i<w.size();i++){ //n_blocks
		v1.push_back(matrix[i_1 + n_lines*i_0 + n_block*i]);
		vk.push_back(matrix[i_k + n_lines*i_0 + n_block*i]);
	}
	
	//==========================================
	//LEARNING METHOD
	total	=	0;
	cout << "LEARNING" << endl;
	for(i=0;i<v1.size();i++){
		if(vk[i]>v1[0]){
			//OK
			w[i]	=	w[i]*105/100;
		}
		else{
			//DECREASE WEIGHT
			w[i]	=	w[i]*95/100;
		}
		cout << w[i] << endl;
		total	+=	w[i];
	}
	
	//==========================================
	ofstream foutw("weight.dat");
	for(i=0;i<w.size();i++){
		foutw << w[i]/total;
		if(i==w.size()-1){
			
		}
		else{
			foutw << endl;
		}
	}
	foutw.close();
	
	//==========================================
}



int MyGraph::LoadXml(string spath,string sfname,string fname_w){
    myreader = new XmlReader(spath,sfname);
    myreader->ReadWeights(fname_w);
    Resize(myreader->getSize());
    myreader->NormaliseWeights();
    PrivateLoader();
    
    return(0);
}
int MyGraph::PrivateLoader(){
    int i,j;
    for(i=0;i<myreader->getSize();i++){
        VVertices[i].SetName(myreader->getName(i));
        for(j=0;j<myreader->getSize();j++){
            AddConnection(i,j,myreader->GetPonderatedEdge(i,j));
            cout << "PondEdg:" << myreader->GetPonderatedEdge(i,j) << endl;
        }
    }
    return(0);
}
int MyGraph::ReloadXml(){
	VVertices.clear();
        myreader->ReloadWeights();
        PrivateLoader();
	return(0);
}
double MyGraph::ChangeIt(bool isTrue,double current,int method){
    switch(method){
        case NOTHING_TODO:
            return(current);
        case MULTIPLY_K:
            if(isTrue){
                return(current*105/100);
            }
            return(current*95/100);
    }
    
}

int MyGraph::WriteXmlW(string fname){
    return(myreader->PutInfile(fname));
}

int MyGraph::LearnXml(int i_0, int i_1, int i_k,int method){
    int i;
    vector<bool> temp;
    temp.resize(myreader->getNm());

    for(i=0;i<myreader->getNm();i++){
        temp[i]=!(myreader->getVal(i_0,i_1,i)>myreader->getVal(i_0,i_k,i));
        cout << myreader->getVal(i_0,i_1,i) << ">" << myreader->getVal(i_0,i_k,i) << "?" << temp[i] << endl;
    }
    for(i=0;i<myreader->getNm();i++){
        myreader->setWeight(i,ChangeIt(temp[i],myreader->getWeight(i),method));
        cout << myreader->getWeight(i) << endl;
    }
    myreader->NormaliseWeights();
    //PAS BESOIN DE RECHARCHER CA
    /*
    //empty the vertices
    VVertices.clear();
    VVertices.resize(myreader->getSize());
    //reload them
    PrivateLoader();
     */
    return(0);
}

int MyGraph::SaveWeights(string fname){
    myreader->PutInfile(fname);
    return(0);
}


